package com.taobao.tql.parser;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TqlParser {

	private static final String Comma = ",";

	/**
	 * 四个空格
	 */
	private static final String FourSpace = "    ";

	/**
	 * 是否单行显示字段，表，条件的标识量
	 */
	private static boolean isSingleLine = true;

	/**
	 * 待解析的tql语句
	 */
	private String tql;

	/**
	 * tql中选择的列
	 */
	private String cols;

	/**
	 * tql中查找的表
	 */
	private String tables;

	/**
	 * 查找条件
	 */
	private String conditions;

	/**
	 * Group By的字段
	 */
	private String groupCols;

	/**
	 * Order by的字段
	 */
	private String orderCols;

	/**
	 * 构造函数 功能：传入构造函数，解析成字段，表，条件等
	 * 
	 * @param tql
	 *            ：传入的tql语句
	 */
	public TqlParser(String tql) {
		this.tql = tql.trim();

		parseCols();
		parseTables();
		parseConditions();
		parseGroupCols();
		parseOrderCols();
	}

	/**
	 * 解析选择的列
	 * 
	 */
	private void parseCols() {
		String regex = "(select)(.+)(from)";
		cols = getMatchedString(regex, tql);
		if(cols != null) {
			cols = cols.trim();
		}
	}

	public String getCols()  {
		return this.cols;
	}
	
	/**
	 * 解析选择的表
	 * 
	 */
	private void parseTables() {
		String regex = "";

		if (isContains(tql, "\\s+where\\s+")) {
			regex = "(from)(.+)(where)";
		} else {
			regex = "(from)(.+)($)";
		}

		tables = getMatchedString(regex, tql);
		if(tables != null) {
			tables = tables.trim();
		}
	}

	
	public String getTables()  {
		return this.tables;
	}
	
	public String getConditions()  {
		return this.conditions;
	}
	/**
	 * 解析查找条件
	 * 
	 */
	private void parseConditions() {
		String regex = "";

		if (isContains(tql, "\\s+where\\s+")) {
			// 包括Where，有条件

			if (isContains(tql, "group\\s+by")) {
				// 条件在where和group by之间
				regex = "(where)(.+)(group\\s+by)";
			} else if (isContains(tql, "order\\s+by")) {
				// 条件在where和order by之间
				regex = "(where)(.+)(order\\s+by)";
			} else {
				// 条件在where到字符串末尾
				regex = "(where)(.+)($)";
			}
		} else {
			// 不包括where则条件无从谈起，返回即可
			return;
		}

		conditions = getMatchedString(regex, tql);
	}

	/**
	 * 解析GroupBy的字段
	 * 
	 */
	private void parseGroupCols() {
		String regex = "";

		if (isContains(tql, "group\\s+by")) {
			// 包括GroupBy，有分组字段

			if (isContains(tql, "order\\s+by")) {
				// group by 后有order by
				regex = "(group\\s+by)(.+)(order\\s+by)";
			} else {
				// group by 后无order by
				regex = "(group\\s+by)(.+)($)";
			}
		} else {
			// 不包括GroupBy则分组字段无从谈起，返回即可
			return;
		}

		groupCols = getMatchedString(regex, tql);
	}

	/**
	 * 解析OrderBy的字段
	 * 
	 */
	private void parseOrderCols() {
		String regex = "";

		if (isContains(tql, "order\\s+by")) {
			// 包括GroupBy，有分组字段
			regex = "(order\\s+by)(.+)($)";
		} else {
			// 不包括GroupBy则分组字段无从谈起，返回即可
			return;
		}

		orderCols = getMatchedString(regex, tql);
	}

	/**
	 * 从文本text中找到regex首次匹配的字符串，不区分大小写
	 * 
	 * @param regex
	 *            ： 正则表达式
	 * @param text
	 *            ：欲查找的字符串
	 * @return regex首次匹配的字符串，如未匹配返回空
	 */
	private static String getMatchedString(String regex, String text) {
		Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);

		Matcher matcher = pattern.matcher(text);

		while (matcher.find()) {
			return matcher.group(2);
		}

		return null;
	}

	/**
	 * 看word是否在lineText中存在，支持正则表达式
	 * 
	 * @param lineText
	 * @param word
	 * @return
	 */
	private static boolean isContains(String lineText, String word) {
		Pattern pattern = Pattern.compile(word, Pattern.CASE_INSENSITIVE);
		Matcher matcher = pattern.matcher(lineText);
		return matcher.find();
	}

	public String toString() {
		// 无法解析则原样返回
		if (cols == null && tables == null && conditions == null && groupCols == null && orderCols == null) {
			return tql;
		}

		StringBuffer sb = new StringBuffer();
		sb.append("原tql为" + tql + "\n");
		sb.append("解析后的tql为\n");

		for (String str : getParsedtqlList()) {
			sb.append(str);
		}

		sb.append("\n");

		return sb.toString();
	}

	/**
	 * 在分隔符后加上回车
	 * 
	 * @param str
	 * @param splitStr
	 * @return
	 */
	private static String getAddEnterStr(String str, String splitStr) {
		Pattern p = Pattern.compile(splitStr, Pattern.CASE_INSENSITIVE);

		// 用Pattern类的matcher()方法生成一个Matcher对象
		Matcher m = p.matcher(str);
		StringBuffer sb = new StringBuffer();

		// 使用find()方法查找第一个匹配的对象
		boolean result = m.find();

		// 使用循环找出模式匹配的内容替换之,再将内容加到sb里
		while (result) {
			m.appendReplacement(sb, m.group(0) + "\n     ");
			result = m.find();
		}
		// 最后调用appendTail()方法将最后一次匹配后的剩余字符串加到sb里；
		m.appendTail(sb);

		return FourSpace + sb.toString();
	}

	/**
	 * 取得解析的tql字符串列表
	 * 
	 * @return
	 */
	public List<String> getParsedtqlList() {
		List<String> tqlList = new ArrayList<String>();

		// 无法解析则原样返回
		if (cols == null && tables == null && conditions == null && groupCols == null && orderCols == null) {
			tqlList.add(tql);
			return tqlList;
		}

		if (cols != null) {
			tqlList.add("select\n");
			if (isSingleLine) {
				tqlList.add(getAddEnterStr(cols, Comma));
			} else {
				tqlList.add(FourSpace + cols);
			}
		}

		if (tables != null) {
			tqlList.add(" \nfrom\n");

			if (isSingleLine) {
				tqlList.add(getAddEnterStr(tables, Comma));
			} else {
				tqlList.add(FourSpace + tables);
			}
		}

		if (conditions != null) {
			tqlList.add(" \nwhere\n");

			if (isSingleLine) {
				tqlList.add(getAddEnterStr(conditions, "(and|or)"));
			} else {
				tqlList.add(FourSpace + conditions);
			}
		}

		if (groupCols != null) {
			tqlList.add(" \ngroup by\n");

			if (isSingleLine) {
				tqlList.add(getAddEnterStr(groupCols, Comma));
			} else {
				tqlList.add(FourSpace + groupCols);
			}
		}

		if (orderCols != null) {
			tqlList.add(" \norder by\n");

			if (isSingleLine) {
				tqlList.add(getAddEnterStr(orderCols, Comma));
			} else {
				tqlList.add(FourSpace + orderCols);
			}
		}

		return tqlList;
	}

	/**
	 * 设置是否单行显示表，字段，条件等
	 * 
	 * @param isSingleLine
	 */
	public static void setSingleLine(boolean isSingleLine) {
		TqlParser.isSingleLine = isSingleLine;
	}

	/**
	 * 测试
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		List<String> ls = new ArrayList<String>();
		ls.add("select * from dual");
		ls.add("SELECT * frOm dual");
		ls.add("Select C1,c2 From tb");
		ls.add("select c1,c2 from tb");
		ls.add("select count(*) from t1");
		ls.add("select c1,c2,c3 from t1.1 where condi1=1 ");
		ls.add("Select c1,c2,c3 From t1 Where condi1=1 ");
		ls.add("select c1,c2,c3 from t1,t2 where condi3=3 or condi4=5 order   by o1,o2");
		ls.add("Select c1,c2,c3 from t1,t2 Where condi3=3 or condi4=5 Order   by o1,o2");
		ls.add("select c1,c2,c3 from t1,t2,t3 where condi1=5 and condi6=6 or condi7=7 group  by g1,g2");
		ls.add("Select c1,c2,c3 From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group  by g1,g2");
		ls.add("Select c1,c2,c3 From t1,t2,t3 Where condi1=5 and condi6=6 or condi7=7 Group  by g1,g2,g3 order  by g2,g3");

		for (String tql : ls) {
			System.out.println(new TqlParser(tql));
			// System.out.println(tql);
		}
	}
}
